package jude.java.money.net;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ConnectException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;

import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpMethodBase;
import org.apache.commons.httpclient.HttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.params.DefaultHttpParams;
import org.apache.commons.httpclient.params.HttpClientParams;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.lang.StringUtils;

public class HttpCampaign {
	private static final String KEY_BASE_URL = "-?BASE URL?-";
	public static final String REQUEST_ENCODING = "UTF-8";
	private static final String[] USER_AGENTS = {
		"Googlebot/2.1 (+http://www.googlebot.com/bot.html)",							//googlebot
		"Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1",			//Firefox4.0.1
		"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; CIBA)",				//
		"",
		"",
	};

	protected HttpClient getHttpClient() {
		DefaultHttpParams.getDefaultParams().setParameter("http.protocol.cookie-policy", CookiePolicy.BROWSER_COMPATIBILITY);
		HttpClient client = new HttpClient();
		HttpConnectionManagerParams p = client.getHttpConnectionManager().getParams();
		p.setConnectionTimeout(30000);
		p.setSoTimeout(60000);
		return client;
	}
	
	protected GetMethod getGetMethod(String url, String referer, boolean follow) {
		GetMethod get = new GetMethod(url);
		initMethod(get, referer);
		get.setFollowRedirects(follow);
		return get;
	}

	
	public void initMethod(HttpMethodBase method, String refererUrl) {
		if (refererUrl != null)
			method.addRequestHeader("Referer", refererUrl);
//		method.addRequestHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; CIBA)");
		method.addRequestHeader("User-Agent", USER_AGENTS[1]);
		method.addRequestHeader("Accept", "	text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
		method.addRequestHeader("Accept-Language", "zh-cn,zh;q=0.5");
		method.addRequestHeader("Accept-Encoding", "gzip, deflate");
		method.addRequestHeader("Accept-Charset", "GB2312,utf-8;q=0.7,*;q=0.7");
		method.addRequestHeader("Keep-Alive", "115");
		method.addRequestHeader("Connection", "	keep-alive");
//		method.addRequestHeader("", "");
//		method.addRequestHeader("", "");
	}
	
	protected PostMethod getPostMethod(String url, List<NameValuePair> params) {
		PostMethod post = new PostMethod(url);
		post.getParams().setParameter(HttpClientParams.HTTP_CONTENT_CHARSET, REQUEST_ENCODING);
		post.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new HttpMethodRetryHandler() {
			@Override
			public boolean retryMethod(HttpMethod method, IOException exception, int executionCount) {
				return !(exception instanceof ConnectException) && executionCount < 3;
			}
		});
		if (params != null)
			post.setRequestBody(params.toArray(new NameValuePair[params.size()]));
		return post;
	}

	protected String execute(HttpClient client, HttpMethodBase method) throws IOException {
		int statusCode = client.executeMethod(method);
		if (statusCode != HttpStatus.SC_OK) {
			System.err.println(statusCode);
			method.releaseConnection();
			return null;
		}
		String resp = getResponse(method, -1);
		method.releaseConnection();
		return resp;
	}
	
	protected String getCharset(HttpMethodBase method) {
		return method.getResponseCharSet();
	}

	protected String getResponse(HttpMethodBase method, int max) throws IOException {
		StringBuilder sb = new StringBuilder();
		char[] buffer = new char[1024];
        int n, t=0;
//		Header[] headers = method.getResponseHeaders();
//		for (int i = 0; i < headers.length; i++) {
//			System.out.println(headers[i].getName() + "=" + headers[i].getValue());
//		}
        InputStream in = method.getResponseBodyAsStream();
        Header h = method.getResponseHeader("Content-Encoding");
        if (h != null && "gzip".equals(h.getValue())) {
        	in = new GZIPInputStream(in);
        }
        InputStreamReader reader = new InputStreamReader(in, getCharset(method));
        while ((n = reader.read(buffer)) > 0) {
        	sb.append(buffer, 0, n);
			t += n;
			if (max > 0 && t >= max)
				break;
        }
        reader.close();
        method.releaseConnection();
        return sb.toString();
	}

	public static Map<String, String> url2map(String url) {
		LinkedHashMap<String, String> r = new LinkedHashMap<String, String>();
		int q = url.indexOf('?');
		if (q == -1) {
			r.put(KEY_BASE_URL, url);
			return r;
		}
		r.put(KEY_BASE_URL, url.substring(0, q));
		String query = url.substring(q + 1);
		String[] qs = StringUtils.split(query, '&');
		for (int i = 0; i < qs.length; i++) {
			String[] pair = StringUtils.split(qs[i], "=", 2);
			if (pair.length > 1)
				r.put(pair[0], pair[1]);
		}
		return r;
	}
	
	public static String map2url(Map<String, String> params) {
		StringBuilder sb = new StringBuilder(params.get(KEY_BASE_URL));
		int n = 0;
		for (Map.Entry<String, String> entry : params.entrySet()) {
			String key = entry.getKey();
			if (KEY_BASE_URL.equals(key))
				continue;
			if (n == 0)
				sb.append('?');
			else
				sb.append('&');
			sb.append(key).append('=').append(entry.getValue());
			n ++;
		}
		return sb.toString();
	}
	
	public static String getUrl(String referer, String url) {
//		if (url == null)
//			return referer;
		if (url != null && url.toLowerCase().startsWith("http://"))
			return url;
		if (referer == null || !referer.toLowerCase().startsWith("http://"))
			return null;
		if (StringUtils.isEmpty(url) || url.startsWith("#"))
			return referer;
		int p = referer.indexOf('?');
		if (p > 0)
			referer = referer.substring(0, p);
		if (url.startsWith("/")) {
			p = referer.indexOf('/', 7);
			if (p == -1)
				return referer + url;
			return referer.substring(0, p) + url;
		} else {
			p = referer.lastIndexOf('/', 7);
			if (p == -1)
				return referer + '/' + url;
			return referer.substring(0, p + 1) + url;
		}
	}
	
}
